package org.skydiveapp;

import java.util.ArrayList;

import org.skydiveapplibrary.R;
import org.skydiveapplibrary.data.Constants;
import org.skydiveapplibrary.data.LogEntryContentProvider;
import org.skydiveapplibrary.ui.NumberDialog;
import org.skydiveapplibrary.ui.NumberDialog.OnNumberSetListener;
import org.skydiveapplibrary.ui.LogEntryListCursorAdapter;

import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.view.ContextThemeWrapper;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.TextView;

import com.actionbarsherlock.app.SherlockListFragment;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuInflater;
import com.actionbarsherlock.view.MenuItem;

public class LogEntryListFragment extends SherlockListFragment implements LoaderManager.LoaderCallbacks<Cursor>
{
	private Cursor mCursor;
	private LogEntryListCursorAdapter mAdapter;
	private onLogEntryEditRequestListener mListener;
	private int highlightRow = -1;
	
	// data
	private boolean isDualDisplay;
	
	public interface onLogEntryEditRequestListener
	{
        public void onLogEntryEditRequest(Bundle args);
    }
	
	// The loader's unique id. Loader ids are specific to the Activity or
	// Fragment in which they reside.
	private static final int LOADER_ID = 1;
	
	// listeners
	private OnClickListener addListener = new OnClickListener()
	{
		@Override
		public void onClick(View view)
		{
			addLogEntry();
		}
	};
	
	private OnClickListener copyListener = new OnClickListener()
	{
		@Override
		public void onClick(View view)
		{
			addNewFromPrevious();
		}
	};
	
	private OnClickListener signListener = new OnClickListener()
	{
		@Override
		public void onClick(View view)
		{
			signEntries();
		}
	};
	
	private OnClickListener goToListener = new OnClickListener()
	{
		@Override
		public void onClick(View view)
		{
			goToEntry();
		}
	};
	
	// goto number listener
	private OnNumberSetListener goToSetListener = new OnNumberSetListener()
	{
		@Override
		public void onNumberSet(NumberDialog dialog, int number)
		{
			moveViewToEntry(number);
		}
	}; 
	
	private OnClickListener cancelListener = new OnClickListener()
	{
		@Override
		public void onClick(View view)
		{
			toggleSignMode();
		}
	};
	
    @Override
    public void onAttach(Activity activity)
    {
        super.onAttach(activity);
        // Check that the container activity has implemented the callback interface
        try {
            mListener = (onLogEntryEditRequestListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString() 
                    + " must implement OnItemSelectedListener");
        }
    }
	
	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);

		mAdapter = new LogEntryListCursorAdapter(getActivity(), mCursor, 0);
		setListAdapter(mAdapter);
		getLoaderManager().initLoader(LOADER_ID, null, this);
	}
	
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
	    		Bundle savedInstanceState)
	{
		View logEntryLeftFrame = getActivity().findViewById(R.id.leftFrame);
		isDualDisplay = logEntryLeftFrame != null;
		
		// Inflate the layout for this fragment
	    View view = inflater.inflate(R.layout.log_entry_list_view, container, false);

	    ((ListView) view.findViewById(android.R.id.list)).setChoiceMode(ListView.CHOICE_MODE_SINGLE);
	    
	    view.findViewById(R.id.logEntryLoadingText).setVisibility(
	    			mAdapter.getCursor() == null ? View.VISIBLE : View.GONE);
	    
		// init ui
		if (isDualDisplay)
			initializeTabletUI(view);
		else
			initializePhoneUI(view);

		return view;
	}

	@Override
    public void onResume()
    {
		super.onResume();

    	if (mAdapter.getSelection().size() > 0)
    			moveViewToEntry(mAdapter.getSelection().get(0)+1);
    	
    	if (mAdapter.multiSelect == true)
			toggleSignMode();
    	
    	getLoaderManager().getLoader(LOADER_ID).forceLoad();
    }
	
	@Override
	public Loader<Cursor> onCreateLoader(int id, Bundle args)
	{
		return new CursorLoader(getActivity(),
				LogEntryContentProvider.CONTENT_URI, null, null, null, null);
	}

	@Override
	public void onLoadFinished(Loader<Cursor> loader, Cursor cursor)
	{
		TextView loadingText = (TextView) getActivity().findViewById(R.id.logEntryLoadingText);		
		
		if (loadingText != null)
			loadingText.setVisibility(View.GONE);
		
		mAdapter.swapCursor(cursor);
		
		if (highlightRow >= 0)
		{
			highlightRow(highlightRow);
			highlightRow = -1;
		}
	}

	@Override
	public void onLoaderReset(Loader<Cursor> loader)
	{
		mAdapter.swapCursor(null);
	}
	
    @Override
	public void onListItemClick(ListView lv, View view, int position, long id)
    {
    	if (mAdapter.multiSelect)
    	{
	       	// update selection
	       	getListView().setItemChecked(position, 
	       			mAdapter.toggleSelection((int)id));
    	}
    	else
    	{
    		Bundle args = new Bundle();
    		args.putInt(Constants.EXTRA_LOG_ENTRY_ID, (int)id);
    		
    		mListener.onLogEntryEditRequest(args);
    	}
    }
	
	public void highlightRow(int logEntryId)
	{
		/*
		 if the highlightRow request is caused by a rotation from 
		 phone to tablet view the cursor will not have loaded yet.
		 Setting hightRow >= -1 will cause the row to be highlighted
		 once the data has been loaded.
		*/
		if (mAdapter.getCursor() != null && mAdapter.getCursor().getCount() > 0)
		{
			getListView().setItemChecked(
					getRowFromLogEntryId(logEntryId), true);
		}
		else
		{
			highlightRow = logEntryId;
		}
	}
	
	public void clearHighlightedRows()
	{
		getListView().clearChoices();
		getLoaderManager().getLoader(LOADER_ID).forceLoad();
	}
	
	private void initializePhoneUI(View view)
	{
		setHasOptionsMenu(true);
	}
    
	private void initializeTabletUI(View view)
	{	
		// add button click listeners
		ImageButton addButton = (ImageButton) view.findViewById(R.id.LogEntryListAddButton);
		addButton.setOnClickListener(addListener);
		
		ImageButton gotoButton = (ImageButton) view.findViewById(R.id.LogEntryListGoToButton);
		gotoButton.setOnClickListener(goToListener);
		
		ImageButton copyButton = (ImageButton) view.findViewById(R.id.LogEntryListCopyButton);
		copyButton.setOnClickListener(copyListener);
		
		ImageButton signButton = (ImageButton) view.findViewById(R.id.LogEntryListSignButton);
		signButton.setOnClickListener(signListener);
		
		ImageButton cancelButton = (ImageButton) view.findViewById(R.id.LogEntryListCancelButton);
		cancelButton.setOnClickListener(cancelListener);
	}
    
    public void toggleSignMode()
	{
    	getListView().clearChoices();
    	mAdapter.clearSelection();
    	
		if (mAdapter.multiSelect)
		{
			getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
			mAdapter.multiSelect = false;
			
			if (isDualDisplay)
			{
				setButtonVisibility(R.id.LogEntryListCancelButton, View.GONE);
				setButtonVisibility(R.id.LogEntryListAddButton, View.VISIBLE);
				setButtonVisibility(R.id.LogEntryListCopyButton, View.VISIBLE);
				setButtonVisibility(R.id.LogEntryListGoToButton, View.VISIBLE);
			}
			else
			{
				getActivity().supportInvalidateOptionsMenu();
			}
		}
		else
		{
			getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
			mAdapter.multiSelect = true;
			
			if (isDualDisplay)
			{			
				setButtonVisibility(R.id.LogEntryListCancelButton, View.VISIBLE);
				setButtonVisibility(R.id.LogEntryListAddButton, View.GONE);
				setButtonVisibility(R.id.LogEntryListCopyButton, View.GONE);
				setButtonVisibility(R.id.LogEntryListGoToButton, View.GONE);
			}
			else
			{
				getActivity().supportInvalidateOptionsMenu();
			}
		}
		getListView().invalidateViews();
	}
	
	private void setButtonVisibility(int id, int visibility)
	{
		ImageButton imageButton = (ImageButton) getView().findViewById(id);
		imageButton.setVisibility(visibility);
	}
    
    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    	inflater.inflate(R.menu.menu_add, menu);
    	inflater.inflate(R.menu.menu_copy, menu);
    	inflater.inflate(R.menu.menu_sign, menu);
    	inflater.inflate(R.menu.menu_goto, menu);
    	inflater.inflate(R.menu.menu_back, menu);
    }
    
    @Override
    public void onPrepareOptionsMenu(Menu menu)
    {
    	Boolean signMode = mAdapter.multiSelect;
    	
    	menu.findItem(R.id.menu_add).setVisible(!signMode);
    	menu.findItem(R.id.menu_copy).setVisible(!signMode);
    	menu.findItem(R.id.menu_goto).setVisible(!signMode);
    	menu.findItem(R.id.menu_back).setVisible(signMode & isDualDisplay);
    }
    
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int itemId = item.getItemId();
		if (itemId == R.id.menu_add)
		{
			addLogEntry();
			return true;
		}
		else if (itemId == R.id.menu_copy)
		{
			addNewFromPrevious();
			return true;
		}
		else if (itemId == R.id.menu_sign)
		{
			signEntries();
			return true;
		}
		else if (itemId == R.id.menu_goto)
		{
			goToEntry();
			return true;
		}
		else if (itemId == R.id.menu_back)
		{
			toggleSignMode();
			return true;
		}
		else
		{
			return super.onOptionsItemSelected(item);
		}
    }
    
    private void addLogEntry()
    {
    	mListener.onLogEntryEditRequest(new Bundle());
    }
    
    private void addNewFromPrevious()
    {
		Bundle args = new Bundle();
		args.putBoolean(Constants.EXTRA_LOG_ENTRY_COPY, true);

		mListener.onLogEntryEditRequest(args);
    }
    
    private void signEntries()
    {
		if (mAdapter.multiSelect == false || mAdapter.getSelection().size() == 0)
		{
			toggleSignMode();
		}
		else
		{
	    	// get selected ids
	    	ArrayList<Integer> logEntryIds = mAdapter.getSelection();
	    	
	    	// start signature activity
	    	Intent intent =  new Intent(getActivity(), SignatureActivity.class);
			intent.putExtra(Constants.EXTRA_SELECTED_LOG_ENTRY_IDS, logEntryIds);
			startActivity(intent);
		}
    }
    
    private void goToEntry()
    {
		// init dialog
		NumberDialog dialog = new NumberDialog(
				new ContextThemeWrapper(getActivity(), R.style.DialogStyle),
				R.string.log_entry_list_goto_title,
				1,
				goToSetListener);
		// show dialog
		dialog.show();
    }
	
    private void moveViewToEntry(int logEntryId)
    {
    	int position = getRowFromLogEntryId(logEntryId);
    	
		getListView().setSelection(position);
    }
    
    private int getRowFromLogEntryId(int logEntryId)
    {
    	int position = 0;
		try
		{
			mAdapter.getCursor().moveToFirst();
			while (mAdapter.getCursor().moveToNext())
			{
				if (mAdapter.getCursor().getInt(1) == logEntryId)
				{
					position = mAdapter.getCursor().getPosition();
				}
			}
		}
		finally
		{
		}
		
		return position;
    }
	
    public boolean isSignatureModeEnabled()
    {
    	return mAdapter.multiSelect;
    }
}